home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hot Super Models
/
Hot Super Models.iso
/
unix
/
x11
/
xv200.tar
/
xv-2.00
/
unsupt
/
VMS
/
ARGPROC.C
next >
Wrap
C/C++ Source or Header
|
1992-01-01
|
13KB
|
542 lines
/*
* @(#)argproc.c 1.0 89/02/01 Mark Pizzolato (mark@infopiz.uucp)
*/
#ifndef lint
char argproc_version[] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
#endif
#include "includes.h" /* System include files, system dependent */
/*
* getredirection() is intended to aid in porting C programs
* to VMS (Vax-11 C) which does not support '>' and '<'
* I/O redirection, along with a command line pipe mechanism
* using the '|' AND background command execution '&'.
* The piping mechanism will probably work with almost any 'filter' type
* of program. With suitable modification, it may useful for other
* portability problems as well.
*
* Author: Mark Pizzolato mark@infopiz.UUCP
*/
struct list_item
{
struct list_item *next;
char *value;
};
int
getredirection(ac, av)
int *ac;
char ***av;
/*
* Process vms redirection arg's. Exit if any error is seen.
* If getredirection() processes an argument, it is erased
* from the vector. getredirection() returns a new argc and argv value.
* In the event that a background command is requested (by a trailing "&"),
* this routine creates a background subprocess, and simply exits the program.
*
* Warning: do not try to simplify the code for vms. The code
* presupposes that getredirection() is called before any data is
* read from stdin or written to stdout.
*
* Normal usage is as follows:
*
* main(argc, argv)
* int argc;
* char *argv[];
* {
* getredirection(&argc, &argv);
* }
*/
{
int argc = *ac; /* Argument Count */
char **argv = *av; /* Argument Vector */
char *ap; /* Argument pointer */
int j; /* argv[] index */
extern int errno; /* Last vms i/o error */
int item_count = 0; /* Count of Items in List */
struct list_item *list_head = 0; /* First Item in List */
struct list_item *list_tail; /* Last Item in List */
char *in = NULL; /* Input File Name */
char *out = NULL; /* Output File Name */
char *outmode = "w"; /* Mode to Open Output File */
int cmargc = 0; /* Piped Command Arg Count */
char **cmargv = NULL;/* Piped Command Arg Vector */
stat_t statbuf; /* fstat buffer */
/*
* First handle the case where the last thing on the line ends with
* a '&'. This indicates the desire for the command to be run in a
* subprocess, so we satisfy that desire.
*/
ap = argv[argc-1];
if (0 == strcmp("&", ap))
exit(background_process(--argc, argv));
if ('&' == ap[strlen(ap)-1])
{
ap[strlen(ap)-1] = '\0';
exit(background_process(argc, argv));
}
/*
* Now we handle the general redirection cases that involve '>', '>>',
* '<', and pipes '|'.
*/
for (j = 0; j < argc; ++j)
{
if (0 == strcmp("<", argv[j]))
{
if (j+1 >= argc)
{
errno = EINVAL;
perror("No input file");
exit(EXIT_ERR);
}
in = argv[++j];
continue;
}
if ('<' == *(ap = argv[j]))
{
in = 1 + ap;
continue;
}
if (0 == strcmp(">", ap))
{
if (j+1 >= argc)
{
errno = EINVAL;
perror("No output file");
exit(EXIT_ERR);
}
out = argv[++j];
continue;
}
if ('>' == *ap)
{
if ('>' == ap[1])
{
outmode = "a";
if ('\0' == ap[2])
out = argv[++j];
else
out = 2 + ap;
}
else
out = 1 + ap;
continue;
}
if (0 == strcmp("|", argv[j]))
{
if (j+1 >= argc)
{
errno = EPIPE;
perror("No command to Pipe to");
exit(EXIT_ERR);
}
cmargc = argc-(j+1);
cmargv = &argv[j+1];
argc = j;
continue;
}
if ('|' == *(ap = argv[j]))
{
++argv[j];
cmargc = argc-j;
cmargv = &argv[j];
argc = j;
continue;
}
expand_wild_cards(ap, &list_head, &list_tail, &item_count);
}
/*
* Allocate and fill in the new argument vector, Some Unix's terminate
* the list with an extra null pointer.
*/
argv = *av = calloc(item_count+1, sizeof(char *));
for (j = 0; j < item_count; ++j, list_head = list_head->next)
argv[j] = list_head->value;
*ac = item_count;
if (cmargv != NULL)
{
char subcmd[1024];
static char *pipe_and_fork();
if (out != NULL)
{
errno = EINVAL;
perror("Invalid '|' and '>' specified");
exit(EXIT_ERR);
}
strcpy(subcmd, cmargv[0]);
for (j = 1; j < cmargc; ++j)
{
strcat(subcmd, " \"");
strcat(subcmd, cmargv[j]);
strcat(subcmd, "\"");
}
out = pipe_and_fork(subcmd);
outmode = "wb";
}
/* Check for input from a pipe (mailbox) */
if(fstat(0, &statbuf) == 0){
if(strncmp(statbuf.st_dev, "MB", 2) == 0 ||
strncmp(statbuf.st_dev, "_MB", 3) == 0){
/* Input from a pipe, reopen it in binary mode to disable */
/* carriage control processing. */
if (in != NULL){
errno = EINVAL;
perror("Invalid '|' and '<' specified");
exit(EXIT_ERR);
}
freopen(statbuf.st_dev, "rb", stdin);
}
}
else {
perror("fstat failed");
exit(EXIT_ERR);
}
if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2")))
{
perror(in); /* Can't find file */
exit(EXIT_ERR); /* Is a fatal error */
}
if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "mbf=2")))
{
perror(ap); /* Error, can't write or append */
exit(EXIT_ERR); /* Is a fatal error */
}
#ifdef DEBUG
fprintf(stderr, "Arglist:\n");
for (j = 0; j < *ac; ++j)
fprintf(stderr, "argv[%d] = '%s'\n", j, argv[j]);
#endif
}
static add_item(head, tail, value, count)
struct list_item **head;
struct list_item **tail;
char *value;
int *count;
{
if (*head == 0)
{
if (NULL == (*head = calloc(1, sizeof(**head))))
{
errno = ENOMEM;
perror("");
exit(EXIT_ERR);
}
*tail = *head;
}
else
if (NULL == ((*tail)->next = calloc(1, sizeof(**head))))
{
errno = ENOMEM;
perror("");
exit(EXIT_ERR);
}
else
*tail = (*tail)->next;
(*tail)->value = value;
++(*count);
}
static expand_wild_cards(item, head, tail, count)
char *item;
struct ltem_list **head;
struct ltem_list **tail;
int *count;
{
int expcount = 0;
int context = 0;
int status;
int status_value;
int had_version;
$DESCRIPTOR(filespec, item);
$DESCRIPTOR(defaultspec, "SYS$DISK:[]*.*;");
$DESCRIPTOR(resultspec, "");
if (strcspn(item, "*%") == strlen(item))
{
add_item(head, tail, item, count);
return;
}
resultspec.dsc$b_dtype = DSC$K_DTYPE_T;
resultspec.dsc$b_class = DSC$K_CLASS_D;
resultspec.dsc$a_pointer = NULL;
filespec.dsc$w_length = strlen(item);
/*
* Only return version specs, if the caller specified a version
*/
had_version = strchr(item, ';');
while (1 == (1&lib$find_file(&filespec, &resultspec, &context,
&defaultspec, 0, &status_value, &0)))
{
char *string;
char *c;
if (NULL == (string = calloc(1, resultspec.dsc$w_length+1)))
{
errno = ENOMEM;
perror("");
exit(EXIT_ERR);
}
strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length);
string[resultspec.dsc$w_length] = '\0';
if (NULL == had_version)
*((char *)strrchr(string, ';')) = '\0';
/*
* Be consistent with what the C RTL has already done to the rest of
* the argv items and lowercase all of these names.
*/
for (c = string; *c; ++c)
if (isupper(*c))
*c = tolower(*c);
add_item(head, tail, string, count);
++expcount;
}
if (expcount == 0)
add_item(head, tail, item, count);
lib$sfree1_dd(&resultspec);
lib$find_file_end(&context);
}
static int child_st[2]; /* Event Flag set when child process completes */
static short child_chan;/* I/O Channel for Pipe Mailbox */
static exit_handler(status)
int *status;
{
short iosb[4];
if (0 == child_st[0])
{
#ifdef DEBUG
fprintf(stderr, "Waiting for Child Process to Finnish . . .\n");
#endif
fflush(stdout); /* Have to flush pipe for binary data to */
/* terminate properly -- <tp@mccall.com> */
sys$qiow(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
sys$dassgn(child_chan);
fclose(stdout);
sys$synch(0, child_st);
}
}
#include syidef /* System Information Definitions */
static sig_child(chan)
int chan;
{
#ifdef DEBUG
fprintf(stderr, "Child Completion AST\n");
#endif
if (child_st[0] == 0)
child_st[0] = 1;
}
static struct exit_control_block
{
struct exit_control_block *flink;
int (*exit_routine)();
int arg_count;
int *status_address;
int exit_status;
} exit_block =
{
0,
exit_handler,
1,
&exit_block.exit_status,
0
};
static char *pipe_and_fork(cmd)
char *cmd;
{
$DESCRIPTOR(cmddsc, cmd);
static char mbxname[64];
$DESCRIPTOR(mbxdsc, mbxname);
short iosb[4];
int status;
int pid;
struct
{
short dna_buflen;
short dna_itmcod;
char *dna_buffer;
short *dna_retlen;
int listend;
} itmlst =
{
sizeof(mbxname),
DVI$_DEVNAM,
mbxname,
&mbxdsc.dsc$w_length,
0
};
int mbxsize;
struct
{
short mbf_buflen;
short mbf_itmcod;
int *mbf_maxbuf;
short *mbf_retlen;
int listend;
} syiitmlst =
{
sizeof(mbxsize),
SYI$_MAXBUF,
&mbxsize,
0,
0
};
cmddsc.dsc$w_length = strlen(cmd);
/*
* Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
* the size of the 'pipe' mailbox.
*/
if (1 == (1&(vaxc$errno = sys$getsyiw(0, 0, 0, &syiitmlst, iosb, 0, 0, 0))))
vaxc$errno = iosb[0];
if (0 == (1&vaxc$errno))
{
errno = EVMSERR;
perror("Can't get SYSGEN parameter value for MAXBUF");
exit(EXIT_ERR);
}
if (mbxsize > 2048)
mbxsize = 2048;
if (0 == (1&(vaxc$errno = sys$crembx(0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
{
errno = EVMSERR;
perror("Can't create pipe mailbox");
exit(EXIT_ERR);
}
if (1 == (1&(vaxc$errno = sys$getdviw(0, child_chan, 0, &itmlst, iosb,
0, 0, 0))))
vaxc$errno = iosb[0];
if (0 == (1&vaxc$errno))
{
errno = EVMSERR;
perror("Can't get pipe mailbox device name");
exit(EXIT_ERR);
}
mbxname[mbxdsc.dsc$w_length] = '\0';
#ifdef DEBUG
fprintf(stderr, "Pipe Mailbox Name = '%s'\n", mbxname);
#endif
if (0 == (1&(vaxc$errno = lib$spawn(&cmddsc, &mbxdsc, 0, &1,
0, &pid, child_st, &0, sig_child,
&child_chan))))
{
errno = EVMSERR;
perror("Can't spawn subprocess");
exit(EXIT_ERR);
}
#ifdef DEBUG
fprintf(stderr, "Subprocess's Pid = %08X\n", pid);
#endif
sys$dclexh(&exit_block);
return(mbxname);
}
background_process(argc, argv)
int argc;
char **argv;
{
char command[2048] = "$";
$DESCRIPTOR(value, command);
$DESCRIPTOR(cmd, "BACKGROUND$COMMAND");
$DESCRIPTOR(null, "NLA0:");
int pid;
strcat(command, argv[0]);
while (--argc)
{
strcat(command, " \"");
strcat(command, *(++argv));
strcat(command, "\"");
}
value.dsc$w_length = strlen(command);
if (0 == (1&(vaxc$errno = lib$set_symbol(&cmd, &value))))
{
errno = EVMSERR;
perror("Can't create symbol for subprocess command");
exit(EXIT_ERR);
}
if (0 == (1&(vaxc$errno = lib$spawn(&cmd, &null, 0, &17, 0, &pid))))
{
errno = EVMSERR;
perror("Can't spawn subprocess");
exit(EXIT_ERR);
}
#ifdef DEBUG
fprintf(stderr, "%s\n", command);
#endif
fprintf(stderr, "%08X\n", pid);
return(EXIT_OK);
}
/* got this off net.sources */
#ifdef VMS
#define index strchr
#endif /*VMS*/
/*
* get option letter from argument vector
*/
int opterr = 1, /* useless, never set or used */
optind = 1, /* index into parent argv vector */
optopt; /* character checked for validity */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define EMSG ""
#define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \
fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
getopt(nargc,nargv,ostr)
int nargc;
char **nargv,
*ostr;
{
static char *place = EMSG; /* option letter processing */
register char *oli; /* option letter list index */
char *index();
if(!*place) { /* update scanning pointer */
if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
if (*place == '-') { /* found "--" */
++optind;
return(EOF);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
if(!*place) ++optind;
tell(": illegal option -- ");
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place) ++optind;
}
else { /* need an argument */
if (*place) optarg = place; /* no white space */
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
tell(": option requires an argument -- ");
}
else optarg = nargv[optind]; /* white space */
place = EMSG;
++optind;
}
return(optopt); /* dump back option letter */
}